//////////////////////////////////////////////////////////////////////////////////
// Author:                          Hector Llanos
// Date:                            08.27.2010
// FileName:                        CBase.cs
// Reason:                          All in game objects will derive from this class
//////////////////////////////////////////////////////////////////////////////////


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using BaseInterface;
using AnimatedSprite;
using Run_Game;

namespace Base
{
    public class CBase : IBaseInterface
    {

        #region PRIVATE_VARS

        /////////////////////////////////////
        //Speed 
        ////////////////////////////////////
        private float m_fSpeedValue = 15.0f;
        private float m_fMaxSpeed;

        ////////////////////////////////////
        // Reference Count
        ////////////////////////////////////
        private uint m_uiRefCount;

        /////////////////////////////////////
        //Object Types
        ////////////////////////////////////
        public enum type
        {
            BASE_OBJECT = 0, 
            
            //PLAYERS
            Player1, Player2, 
            
            //BULLETS
            BASEBULLET, ENEMYBULLET,
            
            ENEMY,MAX_OBJECTS
        } ;

        /////////////////////////////////////
        // Inventory / Key Items
        ////////////////////////////////////
        [Flags]
        public enum Items
        {
            NONE = 0x0,
            BOOK = 0x1, 
            DUCK = 0x2, 
            PEWPEW = 0x4,
            BANGBANG = 0x8,
        };

        private Items m_eKeyItems;

        /////////////////////////////////////
        //Position
        ////////////////////////////////////
        private Vector2 m_vPosition;

        ////////////////////////////////////
        //Velocity
        ////////////////////////////////////
        private Vector2 m_vVelocity;

        ////////////////////////////////////
        //Width/ Height
        ////////////////////////////////////
        private int m_nWidth;
        private int m_nHeight;

        private float m_fScale;
       
        ////////////////////////////////////
        // Animation object
        ////////////////////////////////////
        private AnimatedTexture m_pAnimtion;

        //for collision
        private Texture2D square;

        ////////////////////////////////////
        // Type
        ///////////////////////////////////
        private type m_nType;

        ////////////////////////////////////
        // Collision Rect
        ///////////////////////////////////
        public Rectangle m_rRect;

        float m_fHeading;

        #endregion
        #region PROPERTIES
        /// <Properties>
        /// Function:		Properties
        ///
        /// Purpose:		to get the specified type. / to set the specified type.
        /// </Properties>
        public Items KeyItems
        {
            get { return m_eKeyItems; }
            set { m_eKeyItems = value; }
        }
        public Vector2 Position
        {
            get { return m_vPosition; }
            set { m_vPosition = value; }
        }
        public float PositionX
        {
            get { return m_vPosition.X; }
            set { m_vPosition.X = value; }
        }
        public float PositionY
        {
            get { return m_vPosition.Y; }
            set { m_vPosition.Y = value; }
        }
        public Vector2 Velocity
        {
            get { return m_vVelocity; }
            set { m_vVelocity = value; }
        }
        public int Width
        {
            get { return m_nWidth; }
            set { m_nWidth = value; }
        }
        public int Height
        {
            get { return m_nHeight; }
            set { m_nHeight = value; }
        }
        public float Scale
        {
            get { return m_fScale; }
            set { m_fScale = value; }
        }
        public type Type
        {
            get { return m_nType; }
            set { m_nType = value; }
        }
        public AnimatedTexture Animtion
        {
            get { return m_pAnimtion; }
            set { m_pAnimtion = value; }
        }
        /// <summary>
        /// Maximum magnitude of velocity for this ship.
        /// </summary>
        public float MaxSpeed
        {
            get { return m_fMaxSpeed; }
            set { m_fMaxSpeed = value; }
        }
        /// <summary>
        /// The magnitude of velocity this ship will adhere to for its current task force
        /// </summary>
        public float Speed
        {
            get { return m_fSpeedValue; }
            set
            {
                if (value <= MaxSpeed && value > 0)
                    m_fSpeedValue = value;
                else
                    m_fSpeedValue = MaxSpeed;
            }
        }
        /// <summary>
        /// Sets the facing (a.k.a rotation) of this object.  Value is in radians.
        /// </summary>
        public float Heading
        {
            get { return m_fHeading; }
            set
            {
                m_fHeading = value;
                while (m_fHeading >= System.Math.PI)
                    m_fHeading -= Convert.ToSingle(System.Math.PI) * 2f;
                while (m_fHeading <= -System.Math.PI)
                    m_fHeading += Convert.ToSingle(System.Math.PI) * 2f;
            }
        }
        public Rectangle Rect
        {
            get
            {
                m_rRect = new Rectangle((int)PositionX, (int)PositionY, Width, Height);
                return m_rRect;
            }
        }
        #endregion

        #region HELPER FUNCTIONS
        public Vector2 GetForward()
        {
            return new Vector2(Convert.ToSingle(System.Math.Cos(Heading)), Convert.ToSingle(System.Math.Sin(Heading)));
        }
        public void SetHeadingFromVector2(Vector2 forward)
        {
            if (forward == Vector2.Zero)
                return;

            float futureHeading = 0;
            forward.Normalize();
            if (forward.Y < 0)
                futureHeading = Convert.ToSingle(-System.Math.Acos(forward.X));
            else
                futureHeading = Convert.ToSingle(System.Math.Acos(forward.X));

            if (Single.IsNaN(m_fHeading))
            {
                futureHeading = 0;
                return;
            }
            Heading = futureHeading;
        }
        public void RemoveFlags(Items nMask)
        {
            // TODO: turn off bit(s) 
            // Note: If the bits were already off, this should not turn it on, in other words, do not "toggle".
            if ((m_eKeyItems & nMask) == nMask)
                m_eKeyItems &= ~nMask;
        }
        public void AddFlags(Items nMask)
        {
            // TODO: turn on bit(s)
            // Note: If the bits are already on, this should not turn it off, in other words, do not "toggle".
            if ((m_eKeyItems & nMask) != nMask)
                m_eKeyItems ^= nMask;
        }
        public bool AreFlagsSet(Items nMask)
        {
            // TODO: determine if the nMask bit(s) are set in this class object. 
            return (m_eKeyItems & nMask) != Items.NONE;
        }
        #endregion
        ///<Constructor>
        /// Function:		Constructor
        /// Arguments:      N/A
        /// Notes:          N/A
        /// Purpose:		sets everything to zero
        ///</Constructor>     
        public CBase()
        {
            m_vPosition = new Vector2(0.0f, 0.0f);
            m_vVelocity = new Vector2(0.0f, 0.0f);
            m_nHeight = 0;
            m_nWidth = 0;
            m_nType = (int)type.BASE_OBJECT;

            m_fMaxSpeed = 25f;

            AddRef();
            
        }

        ///<Constructor>
        /// Function:		Constructor
        /// Arguments:      ContentManager content, string assetName, int nMaxDirX, int nMaxDirY, int nFrameDuration
        /// Notes:          nMaxDirX and nMaxDirY must be at least one to work properly
        /// Purpose:		sets everything to zero, inits the animation, and finds the width and height 
        ///</Constructor> 
        public CBase(ContentManager content, string assetName, int nMaxDirX, int nMaxDirY, int nFrameDuration)
        {
            m_vPosition = new Vector2(0.0f, 0.0f);
            m_vVelocity = new Vector2(0.0f, 0.0f);
            m_nType = (int)type.BASE_OBJECT;
            m_fMaxSpeed = 25f;
            m_fScale = 1.0f;

            AddRef();

            Animtion = new AnimatedTexture(Vector2.Zero, 0.0f, m_fScale, 1.0f, true);
            m_pAnimtion.Load(content, assetName, nMaxDirX, nMaxDirY, nFrameDuration);
            square = content.Load<Texture2D>("square");

            m_nHeight = m_pAnimtion.FrameHeight;
            m_nWidth = m_pAnimtion.FrameWidth;

            m_pAnimtion.Origin = new Vector2(Width / 2, Height / 2);

            m_eKeyItems = Items.NONE;
        }
        ///<Deconstructor>
        /// Function:		Deconstructor
        /// Arguments:      N/A
        /// Notes:          N/A
        /// Purpose:		calls release
        ///</Deconstructor>  
        ~CBase()
        {
            Release();
        }

        ///<Update>
        /// Function:		Update
        /// Arguments:      float fElapsedTime
        /// Notes:          use override keyword to override this function
        /// Purpose:		base class update, applies velocity to the position and finds the heading
        ///</Update>
        public virtual void Update(float fElapsedTime)
        {
            SetHeadingFromVector2(Velocity);

            // force everything within max speed
            if (Velocity.LengthSquared() > Speed * Speed)
            {
                Vector2 vel = new Vector2();
                vel = Velocity;
                vel.Normalize();
                vel *= Speed;
                Velocity = vel;
            }
            m_pAnimtion.Rotation = Heading;

            Position = (Position + (Velocity * (fElapsedTime * Speed)));
        
        }

        ///<Render>
        /// Function:		Render
        /// Arguments:      N/A      
        /// Notes:          use override keyword to override this function
        /// Purpose:		base class Render, maybe used for collision
        ///</Render>
        public virtual void Render()
        {
            //collision rect drawing
            Game1.Instance.SpriteBatch.Draw(square, Position, Rect, Color.SandyBrown, Heading, new Vector2(Width / 2, Height / 2), Scale, SpriteEffects.None, 0f); 
        }

        ///<CheckCollision>
        /// Function:		CheckCollision
        /// Arguments:      CBase pBase     
        /// Notes:          if result is not empty, then there is a collision! use override keyword to override this function
        /// Purpose:		check collision on other objects. 
        ///</CheckCollision>
        public virtual bool CheckCollision(CBase pBase)
        {
            Rectangle result;
        
            result = Rectangle.Intersect(m_rRect, pBase.Rect);

            return !result.IsEmpty;
        }

        ///<AddRef>
        /// Function:		AddRef
        /// Arguments:      N/A   
        /// Notes:          N/A
        /// Purpose:		See how many of me do we have
        ///</AddRef>
        public void AddRef( )
        {
            m_uiRefCount++;
        }

        ///<Release>
        /// Function:		Release
        /// Arguments:      N/A   
        /// Notes:          N/A
        /// Purpose:		clean up memory
        ///</Release>
        public void Release()
        {
            m_uiRefCount--;
		    if(m_uiRefCount == 0)
		    {
		    	System.GC.Collect();
		    }
        }

        ///<Input>
        /// Function:		Input
        /// Arguments:      N/A   
        /// Notes:          use override keyword to override this function
        /// Purpose:		get the input for this object
        ///</Input>
        public virtual void Input()
        {
           
        }


    }
}